<?php declare(strict_types=1);

/**
 * @package RecentComments (Light Portal)
 * @link https://custom.simplemachines.org/index.php?mod=4244
 * @author Bugo <bugo@dragomano.ru>
 * @copyright 2022-2025 Bugo
 * @license https://spdx.org/licenses/GPL-3.0-or-later.html GPL-3.0-or-later
 *
 * @category plugin
 * @version 19.10.25
 */

namespace LightPortal\Plugins\RecentComments;

use Bugo\Compat\Lang;
use Laminas\Db\Sql\Predicate\Expression;
use Laminas\Db\Sql\Select;
use LightPortal\Enums\EntryType;
use LightPortal\Enums\Permission;
use LightPortal\Plugins\Block;
use LightPortal\Plugins\Event;
use LightPortal\Plugins\PluginAttribute;
use LightPortal\UI\Fields\NumberField;
use LightPortal\UI\Fields\RangeField;
use LightPortal\Utils\DateTime;
use LightPortal\Utils\Str;
use LightPortal\Utils\Traits\HasTranslationJoins;

if (! defined('LP_NAME'))
	die('No direct access...');

/**
 * Generated by PluginMaker
 */
#[PluginAttribute(icon: 'fas fa-comments')]
class RecentComments extends Block
{
	use HasTranslationJoins;

	public function prepareBlockParams(Event $e): void
	{
		$e->args->params = [
			'num_comments' => 10,
			'length'       => 80,
		];
	}

	public function validateBlockParams(Event $e): void
	{
		$e->args->params = [
			'num_comments' => FILTER_VALIDATE_INT,
			'length'       => FILTER_VALIDATE_INT,
		];
	}

	public function prepareBlockFields(Event $e): void
	{
		$options = $e->args->options;

		NumberField::make('num_comments', $this->txt['num_comments'])
			->setAttribute('min', 1)
			->setValue($options['num_comments']);

		RangeField::make('length', $this->txt['length'])
			->setAttribute('min', 10)
			->setValue($options['length']);
	}

	public function getData(int $commentsCount, int $length = 80): array
	{
		if (empty($commentsCount))
			return [];

		$latestComments = $this->sql->select()
			->from('lp_comments')
			->columns([
				'page_id',
				'created_at' => new Expression('MAX(created_at)')
			])
			->group('page_id');

		$numCommentsSubquery = $this->sql->select()
			->from('lp_comments')
			->columns([new Expression('COUNT(*)')])
			->where('parent_id = 0')
			->where('page_id = com.page_id');

		$select = $this->sql->select()
			->quantifier(Select::QUANTIFIER_DISTINCT)
			->from(['com' => 'lp_comments'])
			->join(
				['latest_comments' => $latestComments],
				'com.page_id = latest_comments.page_id AND com.created_at = latest_comments.created_at'
			)
			->join(
				['p' => 'lp_pages'],
				'p.page_id = com.page_id',
				['slug'],
				Select::JOIN_LEFT
			)
			->join(
				['mem' => 'members'],
				'mem.id_member = com.author_id',
				['author_name' => new Expression('COALESCE(mem.real_name, ?)', [Lang::$txt['guest_title']])],
				Select::JOIN_LEFT
			)
			->join(
				['par' => 'lp_params'],
				new Expression(
					'par.item_id = com.page_id AND par.type = ? AND par.name = ?',
					['page', 'allow_comments']
				),
				[],
				Select::JOIN_LEFT
			)
			->columns([
				'id', 'page_id', 'created_at',
				'num_comments' => $numCommentsSubquery
			])
			->where([
				'p.status'          => 1,
				'p.deleted_at'      => 0,
				'p.created_at <= ?' => time(),
				'p.entry_type'      => EntryType::DEFAULT->name(),
				'p.permissions'     => Permission::all(),
				'par.value > ?'     => 0,
			])
			->order('com.created_at DESC')
			->limit($commentsCount);

		$this->addTranslationJoins($select, [
			'primary' => 'com.id',
			'entity'  => 'comment',
			'fields'  => ['content'],
		]);

		$result = $this->sql->execute($select);

		$comments = [];
		foreach ($result as $row) {
			Lang::censorText($row['content']);

			$comments[$row['id']] = [
				'link'        => LP_PAGE_URL . $row['slug'] . '#comment=' . $row['id'],
				'message'     => Str::getTeaser($row['content'], $length),
				'created_at'  => $row['created_at'],
				'author_name' => $row['author_name'],
			];
		}

		return $comments;
	}

	public function prepareContent(Event $e): void
	{
		$parameters = $e->args->parameters;

		$comments = $this->userCache($this->name . '_addon_b' . $e->args->id)
			->setLifeTime($e->args->cacheTime)
			->setFallback(fn() => $this->getData(
				Str::typed('int', $parameters['num_comments'], default: 10),
				Str::typed('int', $parameters['length'], default: 80)
			));

		if (empty($comments))
			return;

		echo Str::html('ul', ['class' => $this->name . ' noup'])
			->addHtml(
				implode('', array_map(fn($comment) => Str::html('li', ['class' => 'windowbg'])
					->addHtml(Str::html('a')
						->href($comment['link'])
						->setText($comment['message']))
					->addHtml('<br>')
					->addHtml(Str::html('span', ['class' => 'smalltext'])
						->setText(Lang::$txt['by'] . ' ' . $comment['author_name']))
					->addHtml('<br>')
					->addHtml(Str::html('span', ['class' => 'smalltext'])
						->setText(DateTime::relative($comment['created_at']))), $comments))
			);
	}
}
